#include "funcionesFAT32.h"


/*variables globales de las funciones del PdD*/
FILE * ptr;
size_t result;
/*Fin variables globales*/

/*___________________________________________________________________________*/

/****---------------Boot Region---------------****/

int leer_Boot_Sector(){

	char bootBloque[1024];
	char bootBloque2[1024];

	realizar_pedido_lectura(0, bootBloque);
	printf("Pedi lectura BootSector \n");

	memcpy(bootBloque2,bootBloque,1024);
	(FAT32.tamanioSector) =convertirLittleEndianABigEndianEnVector(bootBloque+0x0B,2);

	(FAT32.sectoresPorCluster) = bootBloque[0x0D]; //little endian no causa efecto en 1byte;

	(FAT32.sectoresReservados) = convertirLittleEndianABigEndianEnVector(bootBloque+0x0E,2);

	(FAT32.sectoresPorFAT)=convertirLittleEndianABigEndianEnVector(bootBloque+0x24,4);

	(FAT32.numClusterDirRoot)= convertirLittleEndianABigEndianEnVector(bootBloque+0x2c,4);

	FAT32.cantidadSectores = convertirLittleEndianABigEndianEnVector(bootBloque+0x20,4);
	printf("Tamaño BootSector Leido: %i\n",FAT32.tamanioSector);
	numClustersLibres=0;

	/*Seteo los valores que pide el enunciado para el FS Information Sector*/
	uint32_t b= (-1);
	b=(swap_uint32(b));

	memcpy(bootBloque2+512+0x1E8,&b,sizeof(uint32_t));
	memcpy(bootBloque2+512+0x1EC,&b,sizeof(uint32_t));

	realizar_pedido_escritura(0, bootBloque2);
	printf("Mande a escribir el BootSector \n");
	printf("Fin BootSector \n");

	return 0;
}

/*___________________________________________________________________________*/

/****---------------Boot Region---------------****/

/*___________________________________________________________________________*/

/****---------------FAT Region---------------****/

int bajar_datos_Cluster_FAT(){
	printf("Fat .\n");
	int i,j,num,cant=0;

	char vector[1024];
	memset(vector,0,1024);

	int cantClusterAccedibles = (FAT32.cantidadSectores - FAT32.sectoresReservados-(2*FAT32.sectoresPorFAT))/FAT32.sectoresPorCluster;



	initBitVector(cantClusterAccedibles);

	for(i=FAT32.sectoresReservados,num=0;(i<FAT32.sectoresReservados+FAT32.sectoresPorFAT)&&((num-2)< cantClusterAccedibles );i+=2){

		if(i%1024==0)
			printf("%i\n",i);

		realizar_pedido_lectura(i/2,vector);

		if(cant <5&&tamanioCache>0){
			agregarCacheFAT(i,vector);
			cant++;

		}
		for(j=0;j<(FAT32.tamanioSector*2);j=j+4,num++){

			if(0x0000000 == convertirLittleEndianABigEndianEnVector(vector+j,4)){
				setSector(num,0);
				numClustersLibres++;
			}
			else{
				setSector(num,1);
				//printf("setee en 1\n");

			}
		}
		memset(vector,0,1024);
	}
	printf("mande %d pedidos:\n",i-32);
	bajarBitVector();
	printf("Fin Fat.\n");
	return 0;
}
/*___________________________________________________________________________*/

int agregarCluster(int *numeroDeCluster,listaClusters * clusters){


	if(clusters->numCluster==0){

		clusters->numCluster=*numeroDeCluster;
		clusters->sig=NULL;
	}

	else{

		while(clusters->sig!=NULL)
			clusters=clusters->sig;

		clusters->sig=malloc(sizeof(listaClusters));
		clusters->sig->numCluster=*numeroDeCluster;
		clusters->sig->sig=NULL;

	}

	return 0;

}

/*___________________________________________________________________________*/

int buscar_Clusters_libres(int cant_clusters,int*vectorLibres){

	down(mutexFAT);
	/*Se da por hecho que ya se controlÃ³ la estructura de fat32_data
	 *y que en la misma figura que hay suficientes clusters libres*/

	FILE* clusters;
	int numCluster,valor,cantLibres;
	clusters=fopen("/home/utn_so/free-sectors", "r+");

	/*los clusters guardados incluyen los dos reservados iniciales y al 2.*/

	for(numCluster=0,cantLibres=0;((valor=fgetc(clusters))!=EOF)&&cantLibres<cant_clusters;numCluster++)
		if (valor=='0'){
			vectorLibres[cantLibres]=numCluster;
			cantLibres++;
			setSector(numCluster,1);

		}

	fclose(clusters);

	if(cantLibres<cant_clusters)
		return 1; //estamos al horno. Se corrompiÃ³ el bitVector.
	else{
		bajarBitVector();

		numClustersLibres-=cantLibres;
		up(mutexFAT);
		return 0;

	}
}

/*___________________________________________________________________________*/

int grabar_FAT(int cluster, int valor){

	int numSector,offset;
	char bloque[1024];

	offset=calcularSectorPosicionCluster(cluster,&numSector);
	if(numSector> numSector/2 +numSector/2)
		offset+=512;
	if(tamanioCache>0){
		int pos;
		pos=buscarFAT(numSector/2);
		if(pos!=(-1)){
			memcpy(bloque,CtablaFAT[pos].FAT,1024);
			actualizarCacheFAT(pos);
		}
		else{
			realizar_pedido_lectura(numSector/2,bloque);
			agregarCacheFAT(numSector/2,bloque);
		}
		memcpy(bloque+offset,&valor,sizeof(uint32_t));
		pos=buscarFAT(numSector/2);
		memcpy(CtablaFAT[pos].FAT,bloque,1024);
		CtablaFAT[pos].modificado=1;
	}
	else{
		realizar_pedido_lectura(numSector/2,bloque);
		memcpy(bloque+offset,&valor,sizeof(uint32_t));
		realizar_pedido_escritura(numSector/2,bloque);

	}

	return 0;
}

/****---------------FAT Region---------------****/

/****---------------Data Region---------------****/

int leerDirectorio(fat32_directory * directorio,int numCluster){

	listaClusters* cadenaClusters=NULL;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
	int tamanioCadena;
	int resultado=1;

	tamanioCadena = conseguirCadenaClusters(cadenaClusters,numCluster);

	for(;(tamanioCadena>0)&&(resultado!=0);tamanioCadena--){
		resultado=leerSectoresDelCluster(calcularPrimerSectorDelCluster(cadenaClusters->numCluster),directorio);
		printf("%i\n",cadenaClusters->numCluster);
		cadenaClusters=cadenaClusters->sig;
	}
	free(cadenaClusters);
	return 0;
}

/*___________________________________________________________________________*/

int conseguirCadenaClusters(listaClusters* cadenaClusters,int numCluster){

	int numSector;
	int offset;
	char bloque[1024];
	int numClusterSig;
    int tamanio = 0;
    int numBloque;
	agregarCluster(&numCluster,cadenaClusters);
	offset=calcularSectorPosicionCluster(numCluster,&numSector);

	if(numSector> ((numSector/2)+(numSector/2))){
		offset+=512;

	}

	if(tamanioCache>0){
		int pos;
		pos=buscarFAT(numSector/2);

		if(pos!=(-1)){
	        memcpy(bloque,CtablaFAT[pos].FAT,1024);
			actualizarCacheFAT(pos);
		}
		else{

			realizar_pedido_lectura(numSector/2,bloque);
			agregarCacheFAT(numSector/2,bloque);
		}
	}
	else{
		realizar_pedido_lectura(numSector/2,bloque);
	}
	numBloque=numSector/2;
	numClusterSig=parsearCluster((bloque+offset));
	tamanio++;

	while(numClusterSig!=0){

		agregarCluster(&numClusterSig,cadenaClusters);
		offset=calcularSectorPosicionCluster(numClusterSig,&numSector);
		if(numSector> ((numSector/2)+(numSector/2))){
				offset+=512;


		}

		if((numSector/2)!=numBloque){
			if(tamanioCache>0){
				int pos;
				pos=buscarFAT(numSector/2);
				if(pos!=(-1)){
					memcpy(bloque,CtablaFAT[pos].FAT,1024);
					actualizarCacheFAT(pos);
				}
				else{
					realizar_pedido_lectura(numSector/2,bloque);
					agregarCacheFAT(numSector/2,bloque);
				}
			}
			else{
				realizar_pedido_lectura(numSector/2,bloque);
			}
			numBloque=numSector/2;
		}
		numClusterSig=parsearCluster((bloque+offset));
		tamanio++;


	}


	return tamanio;
}

/*___________________________________________________________________________*/

int leerSectoresDelCluster(int sectorInicial,fat32_directory * directorio){

	int indice,resultado;
	char bloque[1024];
    int offsetSector;
	for(indice=0;indice<FAT32.sectoresPorCluster;indice+=2){
		realizar_pedido_lectura((sectorInicial+indice)/2,bloque);

		for(offsetSector=0;offsetSector<FAT32.tamanioSector*2;offsetSector+=32){
			resultado= parsearEntradaDirectorio(bloque+offsetSector,directorio);
			if(resultado == VACIA)
				return resultado;
			else if(resultado ==NORMAL){
				fat32_directory*ptr=NULL;
				ptr=directorio;
				while(ptr->sig!=NULL)
					ptr=ptr->sig;
				ptr->LongFN=0;
				if(offsetSector>=FAT32.tamanioSector){
					ptr->numSectorEntrada=sectorInicial+indice+1;
					ptr->offsetEntrada=offsetSector-FAT32.tamanioSector;
				}
				else{
					ptr->numSectorEntrada=sectorInicial+indice;
					ptr->offsetEntrada=offsetSector;
				}

				resultado = 1;

			}
			else if(resultado == LFN){
				fat32_directory*ptr=NULL;
				ptr=directorio;
				while(ptr->sig!=NULL)
					ptr=ptr->sig;
				ptr->LongFN=1;
				if(offsetSector>=FAT32.tamanioSector){
					ptr->numSectorEntrada=sectorInicial+indice+1;
					ptr->offsetEntrada=offsetSector-FAT32.tamanioSector;
				}
				else{
					ptr->numSectorEntrada=sectorInicial+indice;
					ptr->offsetEntrada=offsetSector;
				}
				offsetSector+=32;
				resultado = 1;

			}
			else if(resultado==BORRADA)
				offsetSector+=32;

		}
	}

	return resultado;
}

/*___________________________________________________________________________*/

int parsearEntradaDirectorio(char* entradaDirectorio,fat32_directory *directorio){

	uint8_t i,entrada;
	int resultado;

	memcpy(&entrada,entradaDirectorio,sizeof(uint8_t));
	if(entrada==0x00)
		resultado = VACIA;
	else if(entrada==0xE5)
		resultado = BORRADA;

	else{
		memcpy(&entrada,entradaDirectorio+11,sizeof(uint8_t));
			if(entrada==0x0F){
				char vectorAux[26];
				resultado =LFN;
				memset(vectorAux,0,26);
				memcpy(vectorAux,entradaDirectorio+1,10);
				memcpy(vectorAux+10,entradaDirectorio+0x0E,12);
				memcpy(vectorAux+22,entradaDirectorio+0x1C,4);

				for(i=1;i<26;i++){
					vectorAux[i]=vectorAux[i+i];
					vectorAux[i+1]=0;
				}
				for(i=0;i<26;i++){
									if(vectorAux[i]==' ')
										vectorAux[i]='.';

								}
				cargarEntradaDirectorio(entradaDirectorio,directorio,vectorAux);
			}
			else{
				resultado = NORMAL;
				cargarEntradaDirectorio(entradaDirectorio,directorio,NULL);
			}

	}

return resultado;

}

/*___________________________________________________________________________*/

int calcularPrimerSectorDelCluster(int numCluster){

	return (FAT32.sectoresReservados + FAT32.sectoresPorFAT*2 + (numCluster-2)*FAT32.sectoresPorCluster);

}

/*___________________________________________________________________________*/

float calcularSectorPosicionCluster(int numCluster,int* numSector){

	/*int indice,offset;

	for(indice=0,*numSector=FAT32.sectoresReservados,offset=0;indice<numCluster;indice++){
offset+=4;

		if(offset==512){
			offset=0;
			offset+=4;
			*numSector=*numSector+1;
		}

	}

	return (offset);*/
	float numAux=0;int numAux2;
int cant=(FAT32.tamanioSector/4);
	*numSector=numCluster/ (FAT32.tamanioSector/4)+FAT32.sectoresReservados;

	numAux= ((float)numCluster)/((float)cant);
			numAux2=((int)numCluster/(int)cant);
			numAux=numAux-numAux2;

		numAux=numAux	*(FAT32.tamanioSector/4)*4;
	return numAux;
}

/*___________________________________________________________________________*/

int parsearCluster(char*cluster){

	uint32_t valor=0;
	memcpy(&valor,cluster,sizeof(uint32_t));



	if (valor == 0xffffff8)
		return 0;
		else if(valor == 0xfffffff )
			return 0;
		else if(valor == 0x0000000)
			return 0;
		else if( valor==0xffffff0f)
			return 0;
		//else if(valor>0xFF)
		//	valor=(swap_uint32(valor));

		return valor;

}

/*___________________________________________________________________________*/

int cargarEntradaDirectorio(char* entradaDirectorio,fat32_directory* ptr,char*longfilename){

	char vecAux[4];

	if(ptr->tipo==0){


		if(longfilename!=NULL){
			memset(ptr->nombre,0,17);
			strcpy(ptr->nombre,longfilename);

			if((entradaDirectorio[11+32])==0x20)
					ptr->tipo = ARCHIVO;
			else
				ptr->tipo = DIRECTORIO;

			memcpy(vecAux,entradaDirectorio+32+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+32+0x14,2);

			uint32_t tam=0;
			memcpy(&tam,entradaDirectorio+32+0x1C,4);

			//if(tam>0xff)
			//	ptr->tamanio=swap_uint32(tam);
		//	else
				ptr->tamanio=tam;
			tam=0;

			memcpy(&tam,vecAux,4);

		//	if(tam>0xff)
		//		ptr->numClusterInicial=swap_uint32(tam);
		//	else
				ptr->numClusterInicial=tam;

			ptr->sig = NULL;

		}
		else{

			if (entradaDirectorio[0]==0x2E){
				return 0;

			}
			else{
				memset(ptr->nombre,0,17);
				memcpy(ptr->nombre,entradaDirectorio,8);

				int i;
				for(i=0;i<8&&entradaDirectorio[i]!=' ';i++);
				if((entradaDirectorio[11])==0x20){
					ptr->tipo = ARCHIVO;
					memcpy(ptr->nombre+i,".",1);
					memcpy(ptr->nombre+i+1,entradaDirectorio+8,3);
					ptr->nombre[i+1+3]='\0';

				}
				else{
					ptr->tipo = DIRECTORIO;
				}
			}

			uint32_t tam=0;
			memcpy(vecAux,entradaDirectorio+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+0x14,2);

			memcpy(&tam,entradaDirectorio+0x1C,4);

		//	if(tam>0xff)
			//	ptr->tamanio=swap_uint32(tam);
			//else
				ptr->tamanio=tam;
			tam=0;

			memcpy(&tam,vecAux,4);

		//	if(tam>0xff)
		//		ptr->numClusterInicial=swap_uint32(tam);
		//	else
				ptr->numClusterInicial=tam;

			ptr->sig = NULL;

		}
	}

	else{

		if (entradaDirectorio[0]==0x2E){

				return 0;

			}

		while(ptr->sig!=NULL)
			ptr=ptr->sig;

		if(longfilename!=NULL){
			ptr->sig=malloc(sizeof(fat32_directory));
			memset(ptr->sig->nombre,0,17);
			strcpy(ptr->sig->nombre,longfilename);

			if((entradaDirectorio[11+32])==0x20)
					ptr->sig->tipo = ARCHIVO;
				else
					ptr->sig->tipo = DIRECTORIO;

			memcpy(vecAux,entradaDirectorio+32+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+32+0x14,2);
			uint32_t tam=0;

			memcpy(&tam,entradaDirectorio+32+0x1C,4);

			//if(tam>0xff)
			//	ptr->sig->tamanio=swap_uint32(tam);
			//else
				ptr->sig->tamanio=tam;
			tam=0;

			memcpy(&tam,vecAux,4);

			//if(tam>0xff)
			//	ptr->sig->numClusterInicial=swap_uint32(tam);
			//else
				ptr->sig->numClusterInicial=tam;

			ptr->sig->sig=NULL;

		}
		else{
			
				ptr->sig=malloc(sizeof(fat32_directory));

				memset(ptr->sig->nombre,0,17);
							memcpy(ptr->sig->nombre,entradaDirectorio,8);

							if((entradaDirectorio[11])==0x20){
								ptr->sig->tipo = ARCHIVO;
								int i;
								for(i=0;i<8&&entradaDirectorio[i]!=' ';i++);
								memcpy(ptr->sig->nombre+i,".",1);
								memcpy(ptr->sig->nombre+i+1,entradaDirectorio+8,3);
								ptr->sig->nombre[i+1+3]='\0';
							}
							else{
								ptr->sig->tipo = DIRECTORIO;
							}
			uint32_t tam=0;
			memcpy(vecAux,entradaDirectorio+0x1A,2);
			memcpy(vecAux+2,entradaDirectorio+0x14,2);
			memcpy(&tam,entradaDirectorio+0x1C,4);

			//if(tam>0xff)
			//	ptr->sig->tamanio=swap_uint32(tam);
		//	else
				ptr->sig->tamanio=tam;
			tam=0;

			memcpy(&tam,vecAux,4);

			//if(tam>0xff)
			//	ptr->sig->numClusterInicial=swap_uint32(tam);
			//else
				ptr->sig->numClusterInicial=tam;

			ptr->sig->sig=NULL;

		}

	}

	return 0;

}

/*___________________________________________________________________________*/

uint32_t convertirLittleEndianABigEndianEnVector(char*vector,int tamanioVector){

	uint32_t valor,i;
	int offset;
	uint32_t resultado= 0x00000000;
	uint32_t mask= 0xFF000000;

	for(i=0;i<tamanioVector/2;i++){
		valor=vector[i];
		vector[i]=vector[tamanioVector-1-i];
		vector[tamanioVector-1-i]=valor;
	}

	switch(tamanioVector){
		case 2:offset=16;break;
		case 4:offset = 0;break;
	}

	for(i=0;i<tamanioVector;i++,offset+=8){
		valor= (swap_uint32((uint32_t)vector[i]))>>offset;
		resultado=	resultado |(valor&(mask>>offset));
	}

	return resultado;
}

/*___________________________________________________________________________*/

int buscarEntradaLibre(int numCluster,int* sectorIni,int*offset,int longfn){

	fat32_directory*  directorio=malloc(sizeof(fat32_directory));
	listaClusters* cadenaClusters=NULL;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
	int tamanioCadena;
	int resultado=1;
	int sectorInicial;
	int indice;
	char bloque[1024];
	int offsetSector;
	tamanioCadena = conseguirCadenaClusters(cadenaClusters,numCluster);
	directorio->tipo=0;

	for(;(tamanioCadena>0)&&(resultado!=0);tamanioCadena--){
		sectorInicial=calcularPrimerSectorDelCluster(cadenaClusters->numCluster);
		cadenaClusters=cadenaClusters->sig;
		{

			for(indice=0;indice<FAT32.sectoresPorCluster;indice+=2){
				if(((resultado == VACIA) || (resultado==BORRADA))&&longfn==0){
					free(directorio);free(cadenaClusters);

					if(offsetSector>=FAT32.tamanioSector){
						*sectorIni=sectorInicial+indice+1;
						*offset=offsetSector-FAT32.tamanioSector;
					}
					else{
						*sectorIni=sectorInicial+indice;
						*offset=offsetSector;

					}
					 return 0;

				}
				else if(((resultado == VACIA) || (resultado==BORRADA))&&longfn==1){
					resultado= parsearEntradaDirectorio(bloque+offsetSector+32,directorio);
					if(resultado==VACIA|| resultado==BORRADA){

						free(directorio);free(cadenaClusters);

						if(offsetSector>=FAT32.tamanioSector){
							*sectorIni=sectorInicial+indice+1;
							*offset=offsetSector-FAT32.tamanioSector;
						}
						else{
							*sectorIni=sectorInicial+indice;
							*offset=offsetSector;

						}
						return 0;
					}

				}

				realizar_pedido_lectura((sectorInicial+indice)/2,bloque);

				for(offsetSector=0;offsetSector<FAT32.tamanioSector*2;offsetSector+=32){
					resultado= parsearEntradaDirectorio(bloque+offsetSector,directorio);

					if(((resultado == VACIA) || (resultado==BORRADA))&&longfn==0){
										free(directorio);free(cadenaClusters);

										if(offsetSector>=FAT32.tamanioSector){
											*sectorIni=sectorInicial+indice+1;
											*offset=offsetSector-FAT32.tamanioSector;
										}
										else{
											*sectorIni=sectorInicial+indice;
											*offset=offsetSector;

										}
										 return 0;

									}
									else if(((resultado == VACIA) || (resultado==BORRADA))&&longfn==1){
										resultado= parsearEntradaDirectorio(bloque+offsetSector+32,directorio);
										if(resultado==VACIA|| resultado==BORRADA){

											free(directorio);free(cadenaClusters);

											if(offsetSector>=FAT32.tamanioSector){
												*sectorIni=sectorInicial+indice+1;
												*offset=offsetSector-FAT32.tamanioSector;
											}
											else{
												*sectorIni=sectorInicial+indice;
												*offset=offsetSector;

											}
											return 0;
										}
					}
					else if(resultado == LFN){
						offsetSector+=32;
						resultado = 1;
					}

				}
			}
		}
		
	}

	return 0;
}
